#include "asm_utils.h"
#include "interrupt.h"
#include "stdio.h"
#include "program.h"
#include "thread.h"
#include "sync.h"
Semaphore semaphore[5];
int sta[5];
Semaphore semaphore_p;
Semaphore semaphore_c;
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int count = 0;

// 屏幕IO处理器
STDIO stdio;
// 中断管理器
InterruptManager interruptManager;
// 程序管理器
ProgramManager programManager;

//Semaphore semaphore;

int cheese_burger;





void producer(void *arg) {
    int item;
    int t = 0;
    while (1) {
    	if (t++ == 100000000) {
    		t = 0;
		semaphore_p.P();
        	item = count;
        	buffer[count] = item;
        	count++;
        	printf("Produced: %d at buffer %d\n", buffer[count - 1], item);
		semaphore_c.V();
        }
    }
}

void consumer(void *arg) {
    int item;
    int q = 0;
    while (1) {
    	if (q++ == 100000000) {
    		q = 0;
		semaphore_c.P();
        	item = buffer[count - 1];
        	count--;
        	printf("Consumed: %d at buffer %d\n", item, count);
		semaphore_p.V();
        }
    }
}
void think(int n) {
	int i = 0;
	while(1){
		if (i++ == 100000000){
			break;
		}
	}
	i = 0;
	sta[n] = 1;
}

void phi0(void *arg)
{
    while (1) {
    	if (sta[0] == 0) {
    		printf("phi_0 is thinking\n");
    		think(0);
    	}
    	else if (sta[0] == 1) {
    		while (1) {
    			if (sta[4] != 2 && sta[1] != 2) {
    				break;
    			}
    		}
		sta[0] = 2;
        	semaphore[0].P();
    		semaphore[1].P();
    		int i = 0;
    		printf("phi_0 is eating\n");
    		while(1){
			if (i++ == 100000000){
				break;
			}
		}
		printf("phi_0 finished eating\n");
    		semaphore[0].V();
    		semaphore[1].V();
    		sta[0] = 0;
    	}
    }
}
void phi1(void *arg)
{
    while (1) {
    	if (sta[1] == 0) {
    		printf("phi_1 is thinking\n");
    		think(1);
    	}
    	else if (sta[1] == 1) {
    		while (1) {
    			if (sta[0] != 2 && sta[2] != 2) {
    				break;
    			}
    		}
		sta[1] = 2;
        	semaphore[1].P();
    		semaphore[2].P();
    		int i = 0;
    		printf("phi_1 is eating\n");
    		while(1){
			if (i++ == 100000000){
				break;
			}
		}
		printf("phi_1 finished eating\n");
    		semaphore[1].V();
    		semaphore[2].V();
    		sta[1] = 0;
    	}
    }
}
void phi2(void *arg)
{
    while (1) {
    	if (sta[2] == 0) {
    		printf("phi_2 is thinking\n");
    		think(2);
    	}
    	else if (sta[2] == 1) {
    		while (1) {
    			if (sta[1] != 2 && sta[3] != 2) {
    				break;
    			}
    		}
		sta[2] = 2;
        	semaphore[2].P();
    		semaphore[3].P();
    		int i = 0;
    		printf("phi_2 is eating\n");
    		while(1){
			if (i++ == 100000000){
				break;
			}
		}
		printf("phi_2 finished eating\n");
    		semaphore[2].V();
    		semaphore[3].V();
    		sta[2] = 0;
    	}
    }
}
void phi3(void *arg)
{
    while (1) {
    	if (sta[3] == 0) {
    		printf("phi_3 is thinking\n");
    		think(3);
    	}
    	else if (sta[3] == 1) {
    		while (1) {
    			if (sta[2] != 2 && sta[4] != 2) {
    				break;
    			}
    		}
		sta[3] = 2;
        	semaphore[3].P();
    		semaphore[4].P();
    		int i = 0;
    		printf("phi_3 is eating\n");
    		while(1){
			if (i++ == 100000000){
				break;
			}
		}
		printf("phi_3 finished eating\n");
    		semaphore[3].V();
    		semaphore[4].V();
    		sta[3] = 0;
    	}
    }
}
void phi4(void *arg)
{
    while (1) {
    	if (sta[4] == 0) {
    		printf("phi_4 is thinking\n");
    		think(4);
    	}
    	else if (sta[4] == 1) {
    		while (1) {
    			if (sta[3] != 2 && sta[0] != 2) {
    				break;
    			}
    		}
		sta[4] = 2;
        	semaphore[4].P();
    		semaphore[0].P();
    		int i = 0;
    		printf("phi_4 is eating\n");
    		while(1){
			if (i++ == 100000000){
				break;
			}
		}
		printf("phi_4 finished eating\n");
    		semaphore[4].V();
    		semaphore[0].V();
    		sta[4] = 0;
    	}
    }
}

void eat(int n) {
	int i = 0xfffffff;
	semaphore[n].P();
	printf("phi %d is waiting\n", n);
        while(i){
              i--;
        }
    	semaphore[(n+1)%5].P();
	printf("phi %d finished eating\n", n);
	semaphore[n].V();
    	semaphore[(n+1)%5].V();
}

void phi00(void *arg)
{
    eat(0);
}
void phi01(void *arg)
{
    eat(1);
}
void phi02(void *arg)
{
    eat(2);
}
void phi03(void *arg)
{
    eat(3);
}
void phi04(void *arg)
{
    eat(4);
}

void first_thread(void *arg)
{
    // 第1个线程不可以返回
    stdio.moveCursor(0);
    for (int i = 0; i < 25 * 80; ++i)
    {
        stdio.print(' ');
    }
    stdio.moveCursor(0);
    for (int i = 0; i < 5; i++) {
    semaphore[i].initialize(1);
    sta[i] = 0;
    }

    //programManager.executeThread(phi, nullptr, "second thread", 1);
    programManager.executeThread(phi00, nullptr, "second thread", 1);
    programManager.executeThread(phi01, nullptr, "second thread", 1);
    programManager.executeThread(phi02, nullptr, "second thread", 1);
    programManager.executeThread(phi03, nullptr, "second thread", 1);
    programManager.executeThread(phi04, nullptr, "second thread", 1);

    asm_halt();
}

extern "C" void setup_kernel()
{

    // 中断管理器
    interruptManager.initialize();
    interruptManager.enableTimeInterrupt();
    interruptManager.setTimeInterrupt((void *)asm_time_interrupt_handler);

    // 输出管理器
    stdio.initialize();

    // 进程/线程管理器
    programManager.initialize();

    // 创建第一个线程
    int pid = programManager.executeThread(first_thread, nullptr, "first thread", 1);
    if (pid == -1)
    {
        printf("can not execute thread\n");
        asm_halt();
    }

    ListItem *item = programManager.readyPrograms.front();
    PCB *firstThread = ListItem2PCB(item, tagInGeneralList);
    firstThread->status = RUNNING;
    programManager.readyPrograms.pop_front();
    programManager.running = firstThread;
    asm_switch_thread(0, firstThread);

    asm_halt();
}